package com.example.micrauth.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.example.common.constanst.JwtConstant;
import com.example.common.constanst.RedisConstant;
import com.example.common.utils.JwtUtil;
import com.example.common.utils.RedisCacheUtil;
import com.example.micrapi.feign.SysUserServiceFeign;
import com.example.micrauth.domain.dto.LoginDTO;
import com.example.micrauth.domain.vo.LoginUserVO;
import com.example.micrauth.domain.vo.UserInfoVO;
import com.example.micrauth.service.AuthenticationService;
import com.example.micrauth.domain.vo.RespResult;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @description: 登陆
 * @author: uu
 * @date: 2024/2/28 19:01
 * @version: 1.0
 */
@Service
@Slf4j
public class AuthenticationServiceImpl implements AuthenticationService {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private RedisCacheUtil redisCacheUtil;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private SysUserServiceFeign sysUserServiceFeign;

    @Override
    public Map<String, Object> login(LoginDTO loginDTO, @Nullable String token) {

        LoginUserVO loginUserVo = null;
        Map<String, Object> map = new HashMap<>();
        UserInfoVO userInfoVO = new UserInfoVO();

        //TODO 这里的loginUserVO是直接通过SecurityContext拿到的，下面的loginUserVO是通过username查数据库的，所以下面的loginUserVO.getToken == null，会重复生成token
        try {
            jwtUtil.parseToken(token);
            log.info("Authentication = {}", SecurityContextHolder.getContext().getAuthentication());
            loginUserVo = (LoginUserVO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        } catch (Exception e) {
            log.info("token is expired");
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword());
            Authentication authenticate = authenticationManager.authenticate(authentication);
            loginUserVo = (LoginUserVO) authenticate.getPrincipal();
        }
        // 生成token
        if (ObjectUtil.isNotNull(loginUserVo)) {
            log.info("login loginUserVo = {}", loginUserVo);
            // 存在token
            if (ObjectUtil.isNotNull(loginUserVo.getToken())) {
                log.info("loginUserVO is exist = {}", loginUserVo);
                map.put("token", loginUserVo.getToken());
                BeanUtil.copyProperties(loginUserVo.getSysUser(), userInfoVO);
                map.put("userInfo", userInfoVO);
                return map;
            }
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            map.put(JwtConstant.TOKEN_KEY, uuid);
            token = jwtUtil.createToken(map);
            log.info("jwt create token = {}", token);
            loginUserVo.setToken(token);
            // 更新用户登录时间
            loginUserVo.getSysUser().setLastTime(new Date());
            if (!sysUserServiceFeign.updateLastTime(loginUserVo.getSysUser())) {
                throw new RuntimeException("更行登录时间失败");
            }
            // TODO 将UUID当作redis的key,token当作value存到redis中,用来实现当单点登录,踢人下线,查看在线用户等功能
            redisCacheUtil.setCacheObject(RedisConstant.LOGIN_USER_KEY + uuid, loginUserVo, 30, TimeUnit.MINUTES);
            map.put("token", loginUserVo.getToken());
            BeanUtil.copyProperties(loginUserVo.getSysUser(), userInfoVO);
            map.put("userInfo", userInfoVO);
            return map;
        }

        throw new RuntimeException("认证失败");
    }

    /**
     * @description: 退出登录
     * @date: 2024/3/8 21:43
     */
    @Override
    public RespResult logout(String token) {
        // 通过token解析出uuid的值，在删除redis中用户的信息
        Claims claims = null;
        try {
            claims = jwtUtil.parseToken(token);
            String uuid = claims.get(JwtConstant.TOKEN_KEY).toString();
            Boolean res = (Boolean) jwtUtil.removeLoginUser(uuid);
        } catch (Exception e) {
//            throw new RuntimeException("token 解析错误");
            return RespResult.fail().Msg("token 错误");
        }

        return RespResult.success();
    }


}